from typing import Dict, Any
import json

from constants.consts import USER_AGENT_GITEE, USER_AGENT_GITCODE, HOOK_NAME_MERGE, HOOK_NAME_NOTE


class WebHook:
    """
    解析 Gitee 钩子数据的通用类，支持公共字段和动态扩展字段。
    Gitee钩子对象数据格式参考：https://gitee.com/help/articles/4271#article-header1
    """

    def __init__(self, data: Dict[str, Any]):
        # 动态存储字段
        self.extra_data: Dict[str, Any] = {}
        self._parse_dynamic_fields(data)

        # 常用字段
        self.user_agent = None
        self._hook_name = None
        self._pr_number = None
        self._action = None
        self._action_desc = None
        self._branch = None
        self._comment_body = None
        self._commenter = None
        self._assignees = None
        self._repo_owner = None
        self._repo_name = None
        self._commit_msg = None

    @property
    def hook_name(self):
        if self.user_agent == USER_AGENT_GITEE:
            return self.get("hook_name")
        if self.user_agent == USER_AGENT_GITCODE:
            if self._hook_name == "Merge Request Hook":
                return HOOK_NAME_MERGE
            if self._hook_name == "Note Hook":
                return HOOK_NAME_NOTE

    @property
    def commit_msg(self):
        if self._commit_msg:
            return self._commit_msg
        if self.user_agent == USER_AGENT_GITEE:
            self._commit_msg = self.get("pull_request", {}).get("body")
        if self.user_agent == USER_AGENT_GITCODE:
            self._commit_msg = self.get("merge_request", {}).get("description")
        return self._commit_msg

    @property
    def pr_number(self):
        if self._pr_number:
            return self._pr_number
        if self.user_agent == USER_AGENT_GITEE:
            self._pr_number = self.get("pull_request", {}).get('number')
        if self.user_agent == USER_AGENT_GITCODE:
            self._pr_number = self.get("merge_request", {}).get("iid")
        return self._pr_number

    @property
    def action(self):
        if self._action:
            return self._action
        if self.user_agent == USER_AGENT_GITEE:
            self._action = self.get("action")
        if self.user_agent == USER_AGENT_GITCODE:
            self._action = self.get("merge_request", {}).get('act')
            if self.hook_name == HOOK_NAME_NOTE:
                self._action = "comment"
        return self._action

    @property
    def action_desc(self):
        if self._action_desc:
            return self._action_desc
        if self.user_agent == USER_AGENT_GITEE:
            self._action_desc = self.get("action_desc")
        if self.user_agent == USER_AGENT_GITCODE:
            self._action_desc = self.get("merge_request", {}).get('act_desc')
        return self._action_desc

    @property
    def branch(self):
        if self._branch:
            return self._branch
        if self.user_agent == USER_AGENT_GITEE:
            self._branch = self.get("pull_request", {}).get('base', {}).get('ref')
        if self.user_agent == USER_AGENT_GITCODE:
            if self.get("object_attributes", {}).get("target_branch"):
                self._branch = self.get("object_attributes", {}).get("target_branch")
            else:
                self._branch = self.get("merge_request", {}).get("target_branch")
        return self._branch

    @property
    def repo_owner(self):
        if self._repo_owner:
            return self._repo_owner
        if self.user_agent == USER_AGENT_GITEE:
            self._repo_owner = self.get("pull_request", {}).get('base', {}).get('repo', {}).get('owner', {}).get('name')
        if self.user_agent == USER_AGENT_GITCODE:
            self._repo_owner = self.get("project", {}).get('namespace')
        return self._repo_owner

    @property
    def repo_name(self):
        if self._repo_name:
            return self._repo_name
        if self.user_agent == USER_AGENT_GITEE:
            self._repo_name = self.get("pull_request", {}).get('base', {}).get('repo', {}).get('name')
        if self.user_agent == USER_AGENT_GITCODE:
            self._repo_name = self.get("project", {}).get('name')
        return self._repo_name

    @property
    def comment_body(self):
        if self._comment_body:
            return self._comment_body
        if self.user_agent == USER_AGENT_GITEE:
            self._comment_body = self.get("comment", {}).get('body', '').lower()
        if self.user_agent == USER_AGENT_GITCODE:
            self._comment_body = self.get("object_attributes", {}).get("note")
        return self._comment_body

    @property
    def commenter(self):
        if self._commenter:
            return self._commenter
        if self.user_agent == USER_AGENT_GITEE:
            self._commenter = self.get("comment", {}).get('user', {}).get('html_url')
        if self.user_agent == USER_AGENT_GITCODE:
            self._commenter = self.get("user", {}).get("username")
        return self._commenter

    @property
    def assignees(self):
        if self._assignees:
            return self._assignees
        if self.user_agent == USER_AGENT_GITEE:
            self._assignees = self.get('target_user', {}).get('html_url')
        return self._assignees

    def _parse_dynamic_fields(self, data: Dict[str, Any]) -> None:
        """提取字段到 `extra_data` 字典"""
        for key, value in data.items():
            self.extra_data[key] = value

    def get(self, key: str, default: Any = None) -> Any:
        """安全获取动态字段"""
        return self.extra_data.get(key, default)

    def to_json(self) -> Dict[str, Any]:
        """转换为字典格式（用于序列化）"""
        return {
            "hook_id": self.hook_id,
            "hook_url": self.hook_url,
            "hook_name": self.hook_name,
            "password": self.password,
            "timestamp": self.timestamp,
            "sign": self.sign,
            "repository": self.repository,
            "project": self.project,
            "enterprise": self.enterprise,
            "sender": self.sender,
            **self.extra_data
        }

    @classmethod
    def from_json(cls, json_str: str) -> 'WebHook':
        """从 JSON 字符串解析"""
        data = json.loads(json_str)
        return cls(data)

    def __getattr__(self, name: str) -> Any:
        """动态访问差异字段（例如：data.action）"""
        if name in self.extra_data:
            return self.extra_data[name]
        raise AttributeError(f"'{self.__class__.__name__}' object has no attribute '{name}'")
